import numpy as np
import matplotlib.pyplot as plt
import itertools
import math
def calculate_copeland(node, nodes, edges, directions):
copeland_score = 0
for node2 in nodes:
if node == node2:
continue
if node2 > node:
if directions[edges[(node, node2)]] == "0":
copeland_score += 1
elif directions[edges[(node2, node)]] == "1":
copeland_score += 1
return copeland_score
def calculate_max_copeland(nodes, edges, directions):
return max(calculate_copeland(node, nodes, edges, directions) for node in nodes)
def run_se(nodes, edges, directions):
"""Returns Copeland score of winner on the seeding given by nodes
Edges give indices into directions, and directions is a string consisting of 0s and 1s
(0 indicates that the first item in the pair wins)
"""
orig_nodes = nodes
# Run SE
while len(nodes) > 1:
next_level = []
for i in range(0, len(nodes), 2):
if i + 1 == len(nodes):
next_level.append(nodes[i])
else:
u, v = nodes[i], nodes[i + 1]
if u > v:
u, v = v, u
if directions[edges[(u, v)]] == "0":
next_level.append(u)
else:
next_level.append(v)
nodes = next_level
return calculate_copeland(nodes[0], orig_nodes, edges, directions)
def simulate_all(n):
"""Returns an np array E[d+(F(T))]/(max_{s in S} d+(s)) for every tournament, T, on n nodes
"""
nodes = list(range(n))
edges = {}
num_edges = 0
for i in range(len(nodes)):
for j in range(i + 1, len(nodes)):
u = nodes[i]
v = nodes[j]
edges[(u, v)] = num_edges
num_edges += 1
res = []
format_string = f"{{:0{num_edges}b}}"
for tournament in range(2 ** num_edges):
directions = format_string.format(tournament)
num_seedings = 0
total = 0
for seeding in itertools.permutations(nodes):
total += run_se(seeding, edges, directions)
num_seedings += 1
expected_winner_score = total / num_seedings
max_copeland_score = calculate_max_copeland(nodes, edges, directions)
res.append(expected_winner_score / max_copeland_score)
return np.array(res)
def theoretical_min(n):
return math.log2(n) / (n - 2)
def simulate_visual(num_nodes):
the_min = theoretical_min(num_nodes)
responses = simulate_all(num_nodes)
fig, ax = plt.subplots()
ax.plot(np.sort(responses))
ax.hlines([the_min, np.mean(responses)], 0, len(responses) - 1, color="red")
ax.set_title(f"$n = {num_nodes}$")
print(the_min, np.mean(responses))
plt.show()
simulate_visual(5)
0.7739760316291208 0.9036458333333335
simulate_visual(6)
0.646240625180289 0.9285481770833334
# simulate_visual(7) (probably takes at least 16 GB, not happening)
--------------------------------------------------------------------------- KeyboardInterrupt Traceback (most recent call last) <ipython-input-84-06645b31d39a> in <module> ----> 1 simulate_visual(7) <ipython-input-62-a59b6147fa3f> in simulate_visual(num_nodes) 1 def simulate_visual(num_nodes): 2 the_min = theoretical_min(num_nodes) ----> 3 responses = simulate_all(num_nodes) 4 fig, ax = plt.subplots() 5 ax.plot(np.sort(responses)) <ipython-input-30-a00fe38d3bf4> in simulate_all(n) 62 total = 0 63 for seeding in itertools.permutations(nodes): ---> 64 total += run_se(seeding, edges, directions) 65 num_seedings += 1 66 expected_winner_score = total / num_seedings <ipython-input-30-a00fe38d3bf4> in run_se(nodes, edges, directions) 26 while len(nodes) > 1: 27 next_level = [] ---> 28 for i in range(0, len(nodes), 2): 29 if i + 1 == len(nodes): 30 next_level.append(nodes[i]) KeyboardInterrupt:
# simulate_visual(8) nope
def simulate_sample(n, n_tournaments):
"""Returns an np array E[d+(F(T))]/(max_{s in S} d+(s)) for n_tournaments tournaments, T, on n nodes
"""
np.random.seed(0)
nodes = list(range(n))
edges = {}
num_edges = 0
for i in range(len(nodes)):
for j in range(i + 1, len(nodes)):
u = nodes[i]
v = nodes[j]
edges[(u, v)] = num_edges
num_edges += 1
res = []
format_string = f"{{:0{num_edges}b}}"
for tournament in range(n_tournaments):
directions = format_string.format(np.random.randint(0, 2 ** num_edges))
num_seedings = 0
total = 0
for seeding in itertools.permutations(nodes):
total += run_se(seeding, edges, directions)
num_seedings += 1
expected_winner_score = total / num_seedings
max_copeland_score = calculate_max_copeland(nodes, edges, directions)
res.append(expected_winner_score / max_copeland_score)
return np.array(res)
def simulate_visual_sample(num_nodes, n_tournaments):
the_min = theoretical_min(num_nodes)
responses = simulate_sample(num_nodes, n_tournaments)
fig, ax = plt.subplots()
ax.plot(np.sort(responses))
ax.hlines([the_min, np.mean(responses)], 0, len(responses) - 1, color="red")
ax.set_title(f"$n = {num_nodes}$")
print(the_min, np.min(responses), np.mean(responses))
plt.show()
simulate_visual_sample(5, 2000)
0.7739760316291208 0.7777777777777778 0.9007000000000003
simulate_visual_sample(6, 2000)
0.646240625180289 0.8277777777777777 0.9285333333333333
def simulate_sample_both(n, n_tournaments, n_seedings):
"""Returns an np array E[d+(F(T))]/(max_{s in S} d+(s)) for n_tournaments tournaments, T, on n nodes
with n_seedings per tournament
"""
np.random.seed(0)
nodes = list(range(n))
edges = {}
num_edges = 0
for i in range(len(nodes)):
for j in range(i + 1, len(nodes)):
u = nodes[i]
v = nodes[j]
edges[(u, v)] = num_edges
num_edges += 1
res = []
format_string = f"{{:0{num_edges}b}}"
for tournament in range(n_tournaments):
directions = format_string.format(np.random.randint(0, 2 ** num_edges))
num_seedings = 0
total = 0
for seeding in range(n_seedings):
total += run_se(np.random.permutation(nodes), edges, directions)
num_seedings += 1
expected_winner_score = total / num_seedings
max_copeland_score = calculate_max_copeland(nodes, edges, directions)
res.append(expected_winner_score / max_copeland_score)
return np.array(res)
def simulate_visual_sample_both(num_nodes, n_tournaments, n_seedings):
the_min = theoretical_min(num_nodes)
responses = simulate_sample_both(num_nodes, n_tournaments, n_seedings)
fig, ax = plt.subplots()
ax.plot(np.sort(responses))
ax.hlines([the_min, np.mean(responses)], 0, len(responses) - 1, color="red")
ax.set_title(f"$n = {num_nodes}$")
print(the_min, np.min(responses), np.mean(responses))
plt.show()
for i in range(5, 20):
simulate_visual_sample_both(i, 2000, 100)
0.7739760316291208 0.7133333333333334 0.9047916666666667
0.646240625180289 0.7925 0.9287245833333334
0.5614709844115209 0.762 0.9199922500000001
0.5 0.8019999999999999 0.9119239166666666
0.45284642877747316 0.7333333333333334 0.847405880952381
0.4152410118609203 0.7157142857142856 0.8682582142857143
0.3843812909596997 0.75625 0.8735383829365079
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-82-d1bf7bf76091> in <module> 1 for i in range(5, 20): ----> 2 simulate_visual_sample_both(i, 2000, 100) <ipython-input-78-b68e46f63116> in simulate_visual_sample_both(num_nodes, n_tournaments, n_seedings) 31 def simulate_visual_sample_both(num_nodes, n_tournaments, n_seedings): 32 the_min = theoretical_min(num_nodes) ---> 33 responses = simulate_sample_both(num_nodes, n_tournaments, n_seedings) 34 fig, ax = plt.subplots() 35 ax.plot(np.sort(responses)) <ipython-input-78-b68e46f63116> in simulate_sample_both(n, n_tournaments, n_seedings) 18 format_string = f"{{:0{num_edges}b}}" 19 for tournament in range(n_tournaments): ---> 20 directions = format_string.format(np.random.randint(0, 2 ** num_edges)) 21 num_seedings = 0 22 total = 0 mtrand.pyx in numpy.random.mtrand.RandomState.randint() _bounded_integers.pyx in numpy.random._bounded_integers._rand_int64() ValueError: high is out of bounds for int64